using System;
using System.Collections.Generic;

[Serializable]
public class NPlus
{
    public int l;
    public Number p;

    public NPlus(int l, Number p)
    {
        this.l = l;
        this.p = p;
    }

    public NPlus(int l, double p)
    {
        this.l = l;
        bool isPos;
        string[] numSplit;
        if (p < 0)
        {
            numSplit = p.ToString()[1..].Split('.');
            isPos = false;
        }
        else
        {
            numSplit = p.ToString().Split('.');
            isPos = true;
        }
        this.p = new Number(string.Join("", numSplit), isPos, numSplit[1].Length, true);
    }
}

/// <summary>
/// 大数属性类, 用于存储可能数值会很大的属性值和属性加成值
/// <para>v: 基础属性值</para>
/// <para>tv: 总属性值</para>
/// <para>p: 加成, 分为0-n层加成</para>
/// <para>    0层: 基础加成值, 基础加成百分比</para>
/// <para>    1-n层: 共用一个加成值, n个加成百分比</para>
/// <para>计算公式: tv = (v + p0.num) * (1 + p0.per) * (1 + p1.per) * ... * (1 + pn.per) + valNPlus</para>
/// </summary>
[Serializable]
public class NP
{
    // 基础数值
    public Number v;
    // 基础数值加成, 额外数值加成
    public Number[] vp;
    // 百分比加成
    public LinkedList<NPlus> pp;
    // 总数值
    public Number tv;

    public NP() : this(Number.Zero) { }

    public NP(Number v)
    {
        this.v = v;
        tv = v;
        vp = new Number[2] { Number.Zero, Number.Zero };
        pp = new LinkedList<NPlus>();
    }

    /// <summary>
    /// 增加属性值
    /// </summary>
    public void AddV(Number v)
    {
        SetV(this.v + v);
    }

    /// <summary>
    /// 设置属性值
    /// </summary>
    public void SetV(Number v)
    {
        this.v = v;
        ClacTv();
    }

    /// <summary>
    /// 增加属性加成值
    /// </summary>
    public void AddVP(Number vp0, Number vp1)
    {
        SetVP(vp[0] + vp0, vp[1] + vp1);
    }

    /// <summary>
    /// 设置属性加成值
    /// </summary>
    public void SetVP(Number vp0, Number vp1)
    {
        vp[0] = vp0;
        vp[1] = vp1;
        ClacTv();
    }

    /// <summary>
    /// 增加属性加成
    /// </summary>
    public void AddP(NPlus NPlus)
    {
        // 找到对应的层
        LinkedListNode<NPlus> cur = pp.First;
        while (cur != null)
        {
            // 找到对应的层, 增加属性
            if (cur.Value.l == NPlus.l)
            {
                cur.Value.p += NPlus.p;
                if (cur.Value.p == Number.Zero) { pp.Remove(cur); }
                ClacTv();
                return;
            }
            // 找到更大的层, 插入属性
            else if (cur.Value.l > NPlus.l)
            {
                pp.AddBefore(cur, NPlus);
                ClacTv();
                return;
            }
            // 没有找到对应的层, 继续查找
            else
            {
                cur = cur.Next;
            }
        }
        // 一直没有遇到大于等于的层, 直接添加到最后
        pp.AddLast(NPlus);
        ClacTv();
    }

    public void ClacTv()
    {
        tv = v + vp[0];
        foreach (NPlus _pp in pp)
        {
            tv *= Number.One + _pp.p;
        }
        tv += vp[1];
    }
}

[Serializable]
public class DPlus
{
    public int l;
    public double p;

    public DPlus(int l, double p)
    {
        this.l = l;
        this.p = p;
    }
}

/// <summary>
/// 小数属性类, 用于存储可能数值不会很大的属性值和属性加成值
/// <para>v: 基础属性值</para>
/// <para>tv: 总属性值</para>
/// <para>p: 加成, 分为0-n层加成</para>
/// <para>    0层: 基础加成值, 基础加成百分比</para>
/// <para>    1-n层: 共用一个加成值, n个加成百分比</para>
/// <para>计算公式: tv = (v + p0.num) * (1 + p0.per) * (1 + p1.per) * ... * (1 + pn.per) + valNPlus</para>
/// </summary>
[Serializable]
public class DP
{
    // 基础数值
    public double v;
    // 基础数值加成, 额外数值加成
    public double[] vp;
    // 百分比加成
    public LinkedList<DPlus> pp;
    // 总数值
    public double tv;

    public DP() : this(0) { }

    public DP(double v)
    {
        this.v = v;
        tv = v;
        vp = new double[2] { 0, 0 };
        pp = new LinkedList<DPlus>();
    }

    /// <summary>
    /// 增加属性值
    /// </summary>
    public void AddV(double v)
    {
        SetV(this.v + v);
    }

    /// <summary>
    /// 设置属性值
    /// </summary>
    public void SetV(double v)
    {
        this.v = v;
        ClacTv();
    }

    /// <summary>
    /// 增加属性加成值
    /// </summary>
    public void AddVP(double vp0, double vp1)
    {
        SetVP(vp[0] + vp0, vp[1] + vp1);
    }

    /// <summary>
    /// 设置属性加成值
    /// </summary>
    public void SetVP(double vp0, double vp1)
    {
        vp[0] = vp0;
        vp[1] = vp1;
        ClacTv();
    }

    /// <summary>
    /// 增加属性加成
    /// </summary>
    public void AddP(DPlus NPlus)
    {
        // 找到对应的层
        LinkedListNode<DPlus> cur = pp.First;
        while (cur != null)
        {
            // 找到对应的层, 增加属性
            if (cur.Value.l == NPlus.l)
            {
                cur.Value.p += NPlus.p;
                if (cur.Value.p == 0) { pp.Remove(cur); }
                ClacTv();
                return;
            }
            // 找到更大的层, 插入属性
            else if (cur.Value.l > NPlus.l)
            {
                pp.AddBefore(cur, NPlus);
                ClacTv();
                return;
            }
            // 没有找到对应的层, 继续查找
            else
            {
                cur = cur.Next;
            }
        }
        // 一直没有遇到大于等于的层, 直接添加到最后
        pp.AddLast(NPlus);
        ClacTv();
    }

    public void ClacTv()
    {
        tv = v + vp[0];
        foreach (DPlus _pp in pp)
        {
            tv *= 1 + _pp.p;
        }
        tv += vp[1];
    }
}